package cn.caskm.souvenirshopsystem.service.impl;

import cn.caskm.souvenirshopsystem.config.JwtProperties;
import cn.caskm.souvenirshopsystem.constants.BizConstants;
import cn.caskm.souvenirshopsystem.domain.Result;
import cn.caskm.souvenirshopsystem.domain.dto.LoginFormDTO;
import cn.caskm.souvenirshopsystem.domain.dto.PageDTO;
import cn.caskm.souvenirshopsystem.domain.dto.StudentUserRegisterDTO;
import cn.caskm.souvenirshopsystem.domain.dto.StudentUserUpdateDTO;
import cn.caskm.souvenirshopsystem.domain.po.AdminUser;
import cn.caskm.souvenirshopsystem.domain.po.StudentUser;
import cn.caskm.souvenirshopsystem.domain.query.StudentUserQuery;
import cn.caskm.souvenirshopsystem.domain.vo.StudentUserVO;
import cn.caskm.souvenirshopsystem.enums.StatusEnum;
import cn.caskm.souvenirshopsystem.exceptions.BizException;
import cn.caskm.souvenirshopsystem.mapper.StudentUserMapper;
import cn.caskm.souvenirshopsystem.service.StudentUserService;
import cn.caskm.souvenirshopsystem.utils.JwtUtil;
import cn.caskm.souvenirshopsystem.utils.MD5Util;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Slf4j
@Service
@RequiredArgsConstructor
public class StudentUserServiceImpl extends ServiceImpl<StudentUserMapper, StudentUser> implements StudentUserService {

    private final JwtProperties jwtProperties;

    @Override
    public Result<PageDTO<StudentUserVO>> page(StudentUserQuery query) {
        // 获取参数
        Long pageNum = query.getPageNum();
        if (pageNum == null) {
            pageNum = BizConstants.DEFAULT_PAGE_NUM;
        }
        Long pageSize = query.getPageSize();
        if (pageSize == null) {
            pageSize = BizConstants.DEFAULT_PAGE_SIZE;
        }

        // 查询数据
        Page<StudentUser> page = lambdaQuery()
                .like(StrUtil.isNotBlank(query.getSno()), StudentUser::getSno, query.getSno())
                .like(StrUtil.isNotBlank(query.getName()), StudentUser::getName, query.getName())
                .eq(query.getSex() != null, StudentUser::getSex, query.getSex())
                .eq(query.getVipLevel() != null, StudentUser::getVipLevel, query.getVipLevel())
                .eq(query.getStatus() != null, StudentUser::getStatus, query.getStatus())
                .orderByDesc(StudentUser::getCreateTime)
                .page(new Page<>(pageNum, pageSize));

        List<StudentUser> students = page.getRecords();
        if (CollUtil.isEmpty(students)) {
            return Result.success(PageDTO.empty());
        }

        // 组装VO
        List<StudentUserVO> result = new ArrayList<>(students.size());
        for (StudentUser student : students) {
            StudentUserVO vo = BeanUtil.copyProperties(student, StudentUserVO.class);
            result.add(vo);
        }

        return Result.success(PageDTO.of(result, page.getPages(), page.getTotal()));
    }

    @Override
    public Result<Void> register(StudentUserRegisterDTO registerDTO) {
        // 检查学号是否已存在
        StudentUser existing = lambdaQuery()
                .eq(StudentUser::getSno, registerDTO.getSno())
                .one();
        if (existing != null) {
            throw new BizException("学号已存在");
        }

        // 创建学生用户
        StudentUser student = BeanUtil.copyProperties(registerDTO, StudentUser.class);
        student.setStatus(StatusEnum.ON);
        student.setVipLevel(1); // 默认VIP等级为1
        student.setCreateTime(LocalDateTime.now());
        student.setUpdateTime(LocalDateTime.now());

        save(student);
        return Result.success();
    }

    @Override
    public Result<Void> updateStudentUser(StudentUserUpdateDTO updateDTO) {
        if (updateDTO.getId() == null) {
            throw new BizException("学生用户ID不能为空");
        }

        StudentUser existing = getById(updateDTO.getId());
        if (existing == null) {
            throw new BizException("学生用户不存在");
        }

        // 更新信息
        StudentUser student = BeanUtil.copyProperties(updateDTO, StudentUser.class);
        student.setUpdateTime(LocalDateTime.now());
        updateById(student);

        return Result.success();
    }

    @Override
    public Result<StudentUserVO> getStudentUserDetail(Integer id) {
        StudentUser student = getById(id);
        if (student == null) {
            throw new BizException("学生用户不存在");
        }

        StudentUserVO vo = BeanUtil.copyProperties(student, StudentUserVO.class);
        return Result.success(vo);
    }

    @Override
    public Result<StudentUserVO> getByStudentNo(String sno) {
        StudentUser student = lambdaQuery()
                .eq(StudentUser::getSno, sno)
                .one();
        if (student == null) {
            throw new BizException("学生用户不存在");
        }

        StudentUserVO vo = BeanUtil.copyProperties(student, StudentUserVO.class);
        return Result.success(vo);
    }

    @Override
    public Result<Void> updateStatus(Integer id, StatusEnum status) {
        StudentUser student = getById(id);
        if (student == null) {
            throw new BizException("学生用户不存在");
        }

        student.setStatus(status);
        student.setUpdateTime(LocalDateTime.now());
        updateById(student);

        return Result.success();
    }

    @Override
    public Result<Void> deleteStudentUser(Integer id) {
        StudentUser student = getById(id);
        if (student == null) {
            throw new BizException("学生用户不存在");
        }

        removeById(id);
        return Result.success();
    }

    @Override
    public Result<Void> updateVipLevel(Integer id, Integer vipLevel) {
        StudentUser student = getById(id);
        if (student == null) {
            throw new BizException("学生用户不存在");
        }

        student.setVipLevel(vipLevel);
        student.setUpdateTime(LocalDateTime.now());
        updateById(student);

        return Result.success();
    }

    @Override
    public Result<String> login(LoginFormDTO body) {
        // 校验用户名密码是否为空
        String userName = body.getUserName();
        String password = body.getPassword();
        if (StrUtil.hasBlank(userName, password)) {
            throw new BizException("学号或密码不能为空");
        }

        // 查询登录用户
        StudentUser studentUser = lambdaQuery().eq(StudentUser::getSno, userName).one();
        if (studentUser == null) {
            throw new BizException("学生不存在");
        }

        // 校验是否启用账户
        if (studentUser.getStatus() == StatusEnum.OFF) {
            throw new BizException("账号已停用");
        }

        // 校验密码
        String saltPassword = MD5Util.encodeWithSalt(password, studentUser.getSalt());
        if (!saltPassword.equals(studentUser.getPassword())) {
            throw new BizException("密码错误");
        }

        // 生成JWT token
        Map<String, Object> map = new HashMap<>();
        map.put(BizConstants.USER_INFO, studentUser.getId());
        String token = JwtUtil.createToken(map, jwtProperties.getPrivateKey(), jwtProperties.getTokenTTL());

        // 返回
        return Result.success(token);
    }

    @Override
    public Result<Void> changePassword(Integer userId, String oldPassword, String newPassword, String confirmPassword) {
        // 校验参数
        if (StrUtil.hasBlank(oldPassword, newPassword, confirmPassword)) {
            throw new BizException("密码不能为空");
        }

        // 校验新密码和确认密码是否一致
        if (!newPassword.equals(confirmPassword)) {
            throw new BizException("两次输入的新密码不一致");
        }

        // 查询用户
        StudentUser student = getById(userId);
        if (student == null) {
            throw new BizException("用户不存在");
        }

        // 校验原密码是否正确
        String saltOldPassword = MD5Util.encodeWithSalt(oldPassword, student.getSalt());
        if (!saltOldPassword.equals(student.getPassword())) {
            throw new BizException("原密码错误");
        }

        // 更新密码（使用相同的盐）
        String saltNewPassword = MD5Util.encodeWithSalt(newPassword, student.getSalt());
        student.setPassword(saltNewPassword);
        student.setUpdateTime(LocalDateTime.now());
        updateById(student);

        return Result.success();
    }
}
